package com.zkyc.framework.file.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;

/**
 * 公共方法
 */
public class UploadVerify {
    public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();

    static {
        getAllFileType();  //初始化文件类型信息
    }

    /**
     * [getAllFileType,常见文件头信息]
     */
    private static void getAllFileType() {
        FILE_TYPE_MAP.put("jpg", "FFD8FFE");
        FILE_TYPE_MAP.put("png", "89504E4");
        FILE_TYPE_MAP.put("xls", "504B030");
        FILE_TYPE_MAP.put("doc", "D0CF11E");
        FILE_TYPE_MAP.put("docx", "504B0304");
        FILE_TYPE_MAP.put("pdf", "2550444");
        FILE_TYPE_MAP.put("mp4", "000000");
        FILE_TYPE_MAP.put("xlsx", "504B030");
        FILE_TYPE_MAP.put("jpeg", "89504E4");
        FILE_TYPE_MAP.put("avi", "524946");
        FILE_TYPE_MAP.put("rm", "2E524D");
        FILE_TYPE_MAP.put("rmvb", "2E524D");
        FILE_TYPE_MAP.put("webp", "524946");
    }

    /**
     * getImageFileType,获取图片文件实际类型,若不是图片则返回null
     *
     * @return fileType
     */
    public final static String getImageFileType(File f) {
        if (isImage(f)) {
            try {
                ImageInputStream iis = ImageIO.createImageInputStream(f);
                Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
                if (!iter.hasNext()) {
                    return null;
                }
                ImageReader reader = iter.next();
                iis.close();
                return reader.getFormatName();
            } catch (IOException e) {
                return null;
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * getFileByFile,获取文件类型,包括图片,若格式不是已配置的,则返回null
     *
     * @param file
     * @return fileType
     */
    public final static String getFileByFile(File file) {
        String filetype = null;
        byte[] b = new byte[50];
        try {
            InputStream is = new FileInputStream(file);
            is.read(b);
            filetype = getFileTypeByStream(b);
            is.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filetype;
    }

    /**
     * .获取文件类型,MultipartFile这个类型是页面上传常用到的
     *
     * @param file
     * @return
     */
    public final static String getMultipartFileByFile(MultipartFile file) {
        String filetype = null;
        byte[] b = new byte[50];
        try {
            InputStream is = file.getInputStream();
            is.read(b);
            filetype = getFileTypeByStream(b);
            is.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filetype;
    }

    public final static String getFileTypeByStream(byte[] b) {
        String filetypeHex = String.valueOf(getFileHexString(b));
        System.out.println("文件头:" + filetypeHex);
        Iterator<Map.Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Map.Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return null;
    }

    /**
     * isImage,判断文件是否为图片]
     *
     * @param file
     * @return true 是 | false 否
     */
    public static final boolean isImage(File file) {
        boolean flag = false;
        try {
            BufferedImage bufreader = ImageIO.read(file);
            int width = bufreader.getWidth();
            int height = bufreader.getHeight();
            if (width == 0 || height == 0) {
                flag = false;
            } else {
                flag = true;
            }
        } catch (IOException e) {
            flag = false;
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    public final static String getFileHexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        if (b == null || b.length <= 0) {
            return null;
        }
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }


    /**
     * 文件后缀 支持的类型
     */
    private static final String[] FILE_SUFFIX_SUPPORT = {"xlsx", "xls", "doc", "docx", "avi", "rmvb", "rm", "webp",
            "jpg", "jpeg", "png", "mp4", "pdf"};
    /**
     * 文件名字 需要排除的字符
     */
    private static final String[] FILE_NAME_EXCLUDE = {
            "`", "!", "@", "#", "$", "%", "^", "&",
    };


    /**
     * 上传文件校验大小、名字、后缀
     *
     * @param multipartFile multipartFile
     */
    public static void uploadVerify(MultipartFile multipartFile) {
        // 校验文件是否为空
        if (multipartFile == null) {
            throw new RuntimeException("文件不能为空！");
        }

        // 校验文件名字
        String originalFilename = multipartFile.getOriginalFilename();
        if (originalFilename == null) {
            throw new RuntimeException("文件名字不能为空！");
        }

        if (originalFilename.length() > 50) {
            throw new RuntimeException("文件名称不能超过50字符！");
        }
        boolean nameFlag = false;
        for (String s : FILE_NAME_EXCLUDE) {
            if (originalFilename.contains(s)) {
                nameFlag = true;
                break;
            }
        }
        if (nameFlag) {
            throw new RuntimeException("文件名字不允许出现" + Arrays.toString(FILE_NAME_EXCLUDE) + "关键字！");
        }

        // 校验文件后缀
        if (!originalFilename.contains(".")) {
            throw new RuntimeException("文件不能没有后缀！");
        }
        //文件头
        String suffixHead = getMultipartFileByFile(multipartFile);
        //后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf('.')).replaceAll("\\.", "");
        if (islegal(suffix, true) || islegal(suffixHead, true)) {
            throw new RuntimeException("文件格式仅限于" + Arrays.toString(FILE_SUFFIX_SUPPORT) + "！");
        }

    }

    private static boolean islegal(String suffix, boolean flag) {
        if (StringUtils.isNotBlank(suffix)) {
            for (String s : FILE_SUFFIX_SUPPORT) {
                if (s.equals(suffix.toLowerCase(Locale.ROOT))) {
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }


}

